home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / ip / nfs / nfstrace.shar.Z / nfstrace.shar / rpcspy.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-06  |  29.9 KB  |  1,623 lines

  1. /*
  2.  * rpcspy 11/91
  3.  *
  4.  * release 0.9
  5.  *
  6.  * Matt Blaze
  7.  * Copyright 1991 Matt Blaze.
  8.  * May be freely reproduced for non-commerical use.
  9.  * All other rights, including use for direct commerical advantage or
  10.  * use in a commerical product, are reserved by the author.
  11.  *
  12.  * bug reports, etc -> mab@cs.princeton.edu
  13.  *
  14.  * This is the main module.
  15.  * It is much too long and way too ugly.
  16.  */
  17. #include<sys/types.h>
  18. #include<sys/socket.h>
  19. #include <rpc/rpc.h>
  20. #include<net/if.h>
  21. #include<netinet/in_systm.h>
  22. #include<netinet/in.h>
  23. #include<netinet/ip.h>
  24. #include<netinet/udp.h>
  25. #include<rpc/types.h>
  26. #include<sys/param.h>
  27. #include<sys/time.h>
  28. #include <sys/file.h>
  29. #include <sys/errno.h>
  30. #include <sys/ioctl.h>
  31.  
  32. /* generic handle type. this SEEMS to work most places */
  33. #include <nfs/nfs.h>
  34. typedef struct {
  35.         long val[2];                    /* file system id type */
  36. } fsid_t;
  37. struct fhs {
  38.         fsid_t  f1;
  39.         u_short f2;
  40.         char    f3[4];
  41. };
  42. /* stolen from lots of places */
  43. #define FHMAXDATA   (NFS_FHSIZE - sizeof(struct fhs) + 4)
  44.  
  45. typedef struct sfh {
  46.         fsid_t  fh_fsid;
  47.         u_short fh_len;
  48.         char    fh_data[FHMAXDATA];
  49. }sfh;
  50. #define fhandle_t sfh
  51.  
  52.  
  53. #include <netdb.h>
  54. #include <stdio.h>
  55. #include <signal.h>
  56. #include <strings.h>
  57.  
  58. #include "rpcspy.h"
  59.  
  60. int die();
  61.  
  62. /* defs for arg/reply procs */
  63. int     call_nfs_null(),
  64.     call_nfs_getattr(),
  65.     call_nfs_setattr(),
  66.     call_nfs_root(),
  67.     call_nfs_lookup(),
  68.     call_nfs_readlink(),
  69.     call_nfs_read(),
  70.     call_nfs_writecache(),
  71.     call_nfs_write(),
  72.     call_nfs_create(),
  73.     call_nfs_remove(),
  74.     call_nfs_rename(),
  75.     call_nfs_link(),
  76.     call_nfs_symlink(),
  77.     call_nfs_mkdir(),
  78.     call_nfs_rmdir(),
  79.     call_nfs_readdir(),
  80.     call_nfs_statfs(),
  81.     repl_nfs_null(),
  82.     repl_nfs_getattr(),
  83.     repl_nfs_setattr(),
  84.     repl_nfs_root(),
  85.     repl_nfs_lookup(),
  86.     repl_nfs_readlink(),
  87.     repl_nfs_read(),
  88.     repl_nfs_writecache(),
  89.     repl_nfs_write(),
  90.     repl_nfs_create(),
  91.     repl_nfs_remove(),
  92.     repl_nfs_rename(),
  93.     repl_nfs_link(),
  94.     repl_nfs_symlink(),
  95.     repl_nfs_mkdir(),
  96.     repl_nfs_rmdir(),
  97.     repl_nfs_readdir(),
  98.     repl_nfs_statfs(),
  99.     emit_nfs_null(),
  100.     emit_nfs_getattr(),
  101.     emit_nfs_setattr(),
  102.     emit_nfs_root(),
  103.     emit_nfs_lookup(),
  104.     emit_nfs_readlink(),
  105.     emit_nfs_read(),
  106.     emit_nfs_writecache(),
  107.     emit_nfs_write(),
  108.     emit_nfs_create(),
  109.     emit_nfs_remove(),
  110.     emit_nfs_rename(),
  111.     emit_nfs_link(),
  112.     emit_nfs_symlink(),
  113.     emit_nfs_mkdir(),
  114.     emit_nfs_rmdir(),
  115.     emit_nfs_readdir(),
  116.     emit_nfs_statfs();
  117.  
  118.  
  119. /* tables for the arg/reply procs */
  120.  
  121. int (*nfs_call_proc[])() = {
  122.     call_nfs_null,        /*  0 */
  123.     call_nfs_getattr,    /*  1 */
  124.     call_nfs_setattr,    /*  2 */
  125.     call_nfs_root,        /*  3 */
  126.     call_nfs_lookup,    /*  4 */
  127.     call_nfs_readlink,    /*  5 */
  128.     call_nfs_read,        /*  6 */
  129.     call_nfs_writecache,    /*  7 */
  130.     call_nfs_write,        /*  8 */
  131.     call_nfs_create,    /*  9 */
  132.     call_nfs_remove,    /* 10 */
  133.     call_nfs_rename,    /* 11 */
  134.     call_nfs_link,        /* 12 */
  135.     call_nfs_symlink,    /* 13 */
  136.     call_nfs_mkdir,        /* 14 */
  137.     call_nfs_rmdir,        /* 15 */
  138.     call_nfs_readdir,    /* 16 */
  139.     call_nfs_statfs        /* 17 */
  140. };
  141. int (*nfs_repl_proc[])() = {
  142.     repl_nfs_null,        /*  0 */
  143.     repl_nfs_getattr,    /*  1 */
  144.     repl_nfs_setattr,    /*  2 */
  145.     repl_nfs_root,        /*  3 */
  146.     repl_nfs_lookup,    /*  4 */
  147.     repl_nfs_readlink,    /*  5 */
  148.     repl_nfs_read,        /*  6 */
  149.     repl_nfs_writecache,    /*  7 */
  150.     repl_nfs_write,        /*  8 */
  151.     repl_nfs_create,    /*  9 */
  152.     repl_nfs_remove,    /* 10 */
  153.     repl_nfs_rename,    /* 11 */
  154.     repl_nfs_link,        /* 12 */
  155.     repl_nfs_symlink,    /* 13 */
  156.     repl_nfs_mkdir,        /* 14 */
  157.     repl_nfs_rmdir,        /* 15 */
  158.     repl_nfs_readdir,    /* 16 */
  159.     repl_nfs_statfs        /* 17 */
  160. };
  161.  
  162. int (*nfs_emit_proc[])() = {
  163.     emit_nfs_null,        /*  0 */
  164.     emit_nfs_getattr,    /*  1 */
  165.     emit_nfs_setattr,    /*  2 */
  166.     emit_nfs_root,        /*  3 */
  167.     emit_nfs_lookup,    /*  4 */
  168.     emit_nfs_readlink,    /*  5 */
  169.     emit_nfs_read,        /*  6 */
  170.     emit_nfs_writecache,    /*  7 */
  171.     emit_nfs_write,        /*  8 */
  172.     emit_nfs_create,    /*  9 */
  173.     emit_nfs_remove,    /* 10 */
  174.     emit_nfs_rename,    /* 11 */
  175.     emit_nfs_link,        /* 12 */
  176.     emit_nfs_symlink,    /* 13 */
  177.     emit_nfs_mkdir,        /* 14 */
  178.     emit_nfs_rmdir,        /* 15 */
  179.     emit_nfs_readdir,    /* 16 */
  180.     emit_nfs_statfs        /* 17 */
  181. };
  182.  
  183.  
  184. char *nfs_proc_name[] = {
  185.     "null",
  186.     "getattr",
  187.     "setattr",
  188.     "root",
  189.     "lookup",
  190.     "readlink",
  191.     "read",
  192.     "writecache",
  193.     "write",
  194.     "creat",
  195.     "remove",
  196.     "rename",
  197.     "link",
  198.     "symlink",
  199.     "mkdir",
  200.     "rmdir",
  201.     "readdir",
  202.     "statfs"
  203. };
  204.  
  205. char *stat_name[] = {
  206.     "ok",        /* 0 */
  207. };
  208.  
  209.  
  210. /* data structure for nfs transaction (both call and reply) */
  211. typedef struct nfstrans {
  212.     char src[64], dst[64];    /* with respect to the CALL */
  213.     u_long s, d;        /* in versions of src & dest */
  214.     u_long xid;        /* xid + s + d is a unique identifier */
  215.     u_int uid;
  216.     u_long timestamp;    /* arrival time of the CALL */
  217.     int ser;        /* ditto */
  218.     long proc;        /* what procedure - tag for union */
  219.     union {            /* call/reply struct for each proc */
  220.         struct {    /* nfs_null*/
  221.             int call; /* no args*/
  222.             int repl;
  223.         } null;
  224.         struct {    /* nfs_getattr */
  225.             fhandle_t call;
  226.             struct nfsattrstat reply;
  227.         } getattr;
  228.         struct {    /* nfs_setattr */
  229.             struct nfssaargs call;
  230.             struct nfsattrstat reply;
  231.         } setattr;
  232.         struct {    /* nfs_root */
  233.             int call;
  234.             int reply;
  235.         } root; /* should never get this one */
  236.         struct {    /* nfs_lookup */
  237.             struct nfsdiropargs call;
  238.             struct nfsdiropres reply;
  239.         } lookup;
  240.         struct {    /* nfs_readlink */
  241.             fhandle_t call;
  242.             struct nfsrdlnres reply;
  243.         } readlink;
  244.         struct {    /* nfs_read */
  245.             struct nfsreadargs call;
  246.             struct nfsrdresult reply; /* we ignore data */
  247.         } read;
  248.         struct {    /* nfs_writecache */
  249.             int call;
  250.             int result;
  251.         } writecache; /* should also never get this */
  252.         struct {    /* nfs_write */
  253.             struct nfswriteargs call;
  254.             struct nfsattrstat reply;
  255.         } write;
  256.         struct {    /* nfs_create */
  257.             struct nfscreatargs call;
  258.             struct nfsdiropres reply;
  259.         } create;
  260.         struct {    /* nfs_remove */
  261.             struct nfsdiropargs call;
  262.             enum nfsstat reply;
  263.         } remove;
  264.         struct {    /* nfs_rename */
  265.             struct nfsrnmargs call;
  266.             enum nfsstat reply;
  267.         } rename;
  268.         struct {    /* nfs_link */
  269.             struct nfslinkargs call;
  270.             enum nfsstat reply;
  271.         } link;
  272.         struct {    /* nfs_symlink */
  273.             struct nfsslargs call;
  274.             enum nfsstat reply;
  275.         } symlink;
  276.         struct {    /* nfs_mkdir */
  277.             struct nfscreatargs call;
  278.             struct nfsdiropres reply;
  279.         } mkdir;
  280.         struct {    /* nfs_rmdir */
  281.             struct nfsdiropargs call;
  282.             enum nfsstat reply;
  283.         } rmdir;
  284.         struct {    /* nfs_readdir */
  285.             struct nfsrddirargs call;
  286.             struct nfsrddirres reply;
  287.         } readdir;
  288.         struct {    /* nfs_statfs */
  289.             fhandle_t call;
  290.             struct nfsstatfs reply;
  291.         } statfs;
  292.     } args;
  293.     /* some data blocks so we can just malloc and free once */
  294.     char b1[NFS_MAXPATHLEN];
  295.     char b2[NFS_MAXPATHLEN];
  296.     char b3[NFS_MAXNAMLEN];
  297.     char b4[NFS_MAXNAMLEN];
  298.     char b5[1024];    /* for whatever */
  299.     struct nfstrans *next;
  300. } nfstrans;
  301.  
  302. #define QSIZE 257
  303. static nfstrans *transqueue[QSIZE]; /* hash table of trans queue entries */
  304.  
  305. #define MAXAGE 3        /* nuke any call over MAXAGE secs old */
  306. #define MAXTRANS 1000
  307.  
  308. typedef struct hostrec {
  309.     char name[64];
  310.     u_long addr;
  311.     int handlen;    /* or 0 for generic */
  312.     struct hostrec *next;
  313. } hostcache_t;
  314.  
  315. hostcache_t *hostcache[QSIZE];
  316.  
  317. extern long secs;    /* current time in secs */
  318. extern int ser;    /* packets this second */
  319.  
  320. int defaultsize=0;
  321. int size=0;    /* set before call to emit - used by phandle */
  322.  
  323. int good=0;
  324. int bad=0;
  325.  
  326. int ok=0; notok=0; call=0;
  327. int ngc=0, fgc=0;
  328. int nt=0;
  329. int lastgc=0;
  330. int terseflag=0;
  331.  
  332. char *nuke[64]="Princeton.EDU";
  333. char *host();
  334.  
  335. /*
  336.  * This has the command line processing, the setup code, and the main loop.
  337.  */
  338. main(argc,argv)
  339. int argc;
  340. char **argv;
  341. {
  342.     int efd;
  343.     ether_packet pkt;
  344.     long pb[MTU/sizeof(long)];
  345.     int len;
  346.     int i;
  347.     static char interface[32]=DEFAULT;
  348.     char *flag;
  349.     char *pn;
  350.     char *c;
  351.     int runtime;
  352.  
  353.     pn=argv[0];
  354.     while (--argc) {
  355.         if (**++argv == '-') {    /* flag */
  356.             for (flag = ++*argv; *flag; flag++) {
  357.                 switch (*flag) {
  358.                     case 'c':    /* concise output */
  359.                     terseflag++;
  360.                     break;
  361.                     case 'h':    /* handle size */
  362.                     case 'i':    /* interface */
  363.                     case 't':    /* run time */
  364.                     case 's':    /* suf. to nuke */
  365.                     enq(*flag);
  366.                     break;
  367.                     default:
  368.                     usage(pn);
  369.                     exit(-1);
  370.                 }
  371.             }
  372.         } else {
  373.             switch (deq()) {
  374.                 case -1:
  375.                 usage(pn);
  376.                 exit(-1);
  377.                 case 'h':    /* handle size */
  378.                 if ((c=index(*argv,':')) == NULL) {
  379.                     if(sscanf(*argv,"%d",&defaultsize)!=1) {
  380.                         usage(pn);
  381.                         exit(-1);
  382.                     }
  383.                 } else {
  384.                     *c++='\0';
  385.                     if (sscanf(c,"%d",&size)!=1) {
  386.                         usage(pn);
  387.                         exit(-1);
  388.                     }
  389.                     addsize(*argv,size);
  390.                 }
  391.                 break;
  392.                 case 'i':    /* interface */
  393.                 strcpy(interface,*argv);
  394.                 break;
  395.                 case 't':    /* run time */
  396.                 runtime=atoi(*argv);
  397.                 if (runtime) {
  398.                     signal(SIGALRM,die);
  399.                     alarm(runtime);
  400.                 } else {
  401.                     usage(pn);
  402.                     exit(-1);
  403.                 }
  404.                 break;
  405.                 case 's':    /* nuke */
  406.                 strcpy(nuke,*argv);
  407.                 break;
  408.                 default:    /* should never happen */
  409.                 fprintf(stderr,"Internal error\n");
  410.                 exit(-2);
  411.             }
  412.         }
  413.  
  414.     }
  415.     if ((deq() != -1)) {
  416.         usage(pn);
  417.         exit(-1);
  418.     }
  419.     for (i=0; i<QSIZE; i++) {
  420.         transqueue[i]=NULL;
  421.         hostcache[i]=NULL;
  422.     }
  423.     if ((efd=net_open(interface)) <0) {
  424.         perror(interface);
  425.         exit(1);
  426.     }
  427.     sethostent(1);
  428.  
  429.     /*
  430.      * MAIN LOOP
  431.      */
  432.     while(1) {
  433.         if ((len=net_read(efd,&pkt,MTU))<0) {
  434.             perror("net_read");
  435. #ifdef NIT
  436.             exit(-1);
  437. #else
  438.             /* this is to fix a sporatic ultrix bug */
  439.             printf("# net_read returned <0!\n");
  440.             close(efd);
  441.             fflush(stdout);
  442.             if ((efd=net_open(interface))<0)
  443.                 exit(1);
  444.             continue;
  445. #endif
  446.         }
  447.         bcopy(pkt.data,pb,len);
  448.         if (do_inet(pb,len-14))
  449.             good++;
  450.         else
  451.             bad++;
  452.         ser++;
  453.         if ((nt>MAXTRANS) && ((secs-lastgc)> MAXAGE))
  454.             gc();
  455.     }
  456. }
  457.  
  458. usage(s)
  459.      char *s;
  460. {
  461.     fprintf(stderr,"usage: %s [-t runtime] [-h <handlesize]\n", s);
  462.     fprintf (stderr,"  [-h host:handle] [-i interface] [-s suf] [-c]\n");
  463. }
  464.  
  465.  
  466. #define QS 10
  467. struct {
  468.     int data[QS];
  469.     int head;
  470.     int tail;
  471. } argq = {{0},0,0};
  472.  
  473. enq(f)
  474.      char f;
  475. {
  476.     argq.tail++;
  477.     argq.tail %= QS;
  478.     if (argq.head==argq.tail) {
  479.         fprintf(stderr,"Can't deal with this\n");
  480.         exit(-2);
  481.     }
  482.     argq.data[argq.tail]=f;
  483. }
  484.  
  485. deq()
  486. {
  487.     if (argq.head==argq.tail)
  488.         return -1;
  489.     argq.head++;
  490.     argq.head %= QS;
  491.     return(argq.data[argq.head]);
  492. }
  493.  
  494. typedef struct sizelist {
  495.     char name[64];
  496.     int size;
  497.     struct sizelist *next;
  498. } sizelist;
  499.  
  500. sizelist *firstsize=NULL;
  501.  
  502. /* add to handle size list.
  503.  * should check for duplicates.
  504.  * should really be a hash table.
  505.  */
  506. addsize(h,s)
  507.      char *h;
  508.      int s;
  509. {
  510.     sizelist *sl;
  511.  
  512.     if ((sl=(sizelist *)malloc(sizeof (sizelist))) == NULL) {
  513.         fprintf(stderr,"Give up! can't even malloc handle record\n");
  514.         exit(-2);
  515.     }
  516.     strcpy(sl->name,h);
  517.     sl->size=s;
  518.     sl->next=firstsize;
  519.     firstsize=sl;
  520. }
  521.  
  522. /* look up host- return default size if not found */
  523. hsize(h)
  524.      char *h;
  525. {
  526.     sizelist *sl;
  527.     sl=firstsize;
  528.     while (sl!=NULL) {
  529.         if (strcmp(h,sl->name)==0)
  530.             return sl->size;
  531.         sl=sl->next;
  532.     }
  533.     return defaultsize;
  534. }
  535.     
  536.  
  537.  
  538. do_inet(buf,len)
  539. char *buf;
  540. int len;
  541. {
  542.     struct ip *pkt;
  543.     int hl, plen;
  544.     int offset;
  545.     int proto;
  546.     char *data;
  547.  
  548.     pkt=(struct ip *)buf;
  549.     /* first make sure we have enough of the packet to deal with */
  550.     if (len<sizeof(struct ip))
  551.         return 0;
  552.     hl = pkt->ip_hl*4;
  553.     plen = ntohs(pkt->ip_len);
  554.     if ((len<hl) || ((plen-hl>=8)&&(len<hl+8)))
  555.         return 0;
  556.     offset = htons(pkt->ip_off) & ~IP_DF & ~IP_MF;
  557.     if (offset != 0)
  558.         return 0;    /* make sure it's the first fragment */
  559.     
  560.     proto = pkt->ip_p;
  561.     
  562.     data=(char *)pkt + hl;
  563.     switch (proto) {
  564.         case IPPROTO_UDP:    /* UDP, which is all we know how to deal w/ */
  565.         return(udp(&pkt->ip_src,&pkt->ip_dst,data,len-hl));
  566.         break;
  567.         default:
  568.         return 0;
  569.     }
  570.     return 0;
  571. }
  572.  
  573.  
  574. /*
  575.  * deal with udp packet
  576.  */
  577. udp(s,d,pkt,len)
  578.      struct in_addr *s, *d; /* yes, really */
  579.      char *pkt;
  580.      int len;
  581. {
  582.     char src[255], dst[255];
  583.     struct hostent *n;
  584.     struct udphdr *u;
  585.     struct rpc_msg *r;
  586.     int direction;
  587.     
  588.     /* first, figure out whether its an nfs packet */
  589.     u=(struct udphdr *)pkt;
  590.     r=(struct rpc_msg *) ((char *)pkt+sizeof(struct udphdr));
  591.     
  592.     /*
  593.      * first make sure it's an nfs packet (or whatever else we deal w/).
  594.      * we make the unwholesome assumption that everybody uses NFS_PORT
  595.      * as the nfs port.  this is probably always true (i think).
  596.      * should probably fix this to allow it to be specified at runtime
  597.      * for each server, tho.
  598.      * do some simple sanity checks on the packet first
  599.      */
  600.     direction=ntohl(r->rm_direction); /* this is cheating */
  601.     if (ntohs(u->uh_sport) == NFS_PORT) {
  602.         if (direction != REPLY)
  603.             return 0; /* bad packet */
  604.     } else if (ntohs(u->uh_dport) == NFS_PORT) {
  605.         if (direction != CALL)
  606.             return 0; /* bad packet */
  607.     } else return 0;    /* insert code for other services here */
  608.  
  609.     strcpy(src,host(s));
  610.     strcpy(dst,host(d));
  611.     return (nfs(src,dst,*(int*)s,*(int*)d,r,len-sizeof(struct udphdr)));
  612. }
  613.  
  614.  
  615. /*
  616.  * host name lookup
  617.  */
  618. char *host(h)
  619.      struct in_addr *h;
  620. {
  621.     hostcache_t *cache;
  622.     struct hostent *hr;
  623.     u_long bucket;
  624.     unsigned char *c;
  625.  
  626.     bucket=h->s_addr%QSIZE;
  627.     cache= hostcache[bucket];
  628.     while (cache != NULL) {
  629.         if (cache->addr = h->s_addr)
  630.             return (cache->name);
  631.         cache=cache->next;
  632.     }
  633.     if ((cache = (hostcache_t *)malloc(sizeof(hostcache_t))) == NULL) {
  634.         fprintf(stderr,"No memory for host cache!\n");
  635.         die();
  636.     }
  637.     if ((hr=gethostbyaddr(h,sizeof(u_long),AF_INET)) == NULL) {
  638.         c=(unsigned char*)h;
  639.         sprintf(cache->name,"%d.%d.%d.%d",c[0],c[1],c[2],c[3]);
  640.     } else {
  641.         strcpy(cache->name,hr->h_name);
  642.         eliminate(cache->name,nuke);
  643.     }
  644.     cache->addr = h->s_addr;
  645.     cache->next = hostcache[bucket];
  646.     hostcache[bucket] = cache;
  647.     return(cache->name);
  648. }
  649.  
  650. eliminate(s1,s2)
  651.      char *s1, *s2;
  652. {
  653.     if ((*s1 == '\0') || (*s2=='\0'))
  654.         return;
  655.     while (*++s1)
  656.         if (strcmp(s1,s2)==0) {
  657.             *--s1='\0';
  658.             return;
  659.         }
  660. }
  661.  
  662.  
  663. /*
  664.  * deal with rpc/nfs packet
  665.  */
  666. nfs(src,dst,s,d,b,len)
  667.      char *src;
  668.      char *dst;
  669.      u_long s;    /* we know these are really u_long */
  670.      u_long d;    /* should be in_addr */
  671.      struct rpc_msg *b;
  672.      int len;
  673. {
  674.     static struct rpc_msg rb;
  675.     static struct rpc_msg *r = &rb;
  676.     u_int uid;
  677.     XDR xs;
  678.     int stat=0;
  679.     static char x[MAX_AUTH_BYTES];    /* we should fix this. */
  680.     
  681.     /* first, unxdr the rpc message header */
  682.     xdrmem_create(&xs,b,len,XDR_DECODE);    /* create the stream */
  683.     
  684.     switch (ntohl(b->rm_direction)) { /* we have to peek first */
  685.         case CALL:    /* it's a call, so we have to queue it */
  686.         /* un xdr it */
  687.         r->rm_call.cb_cred.oa_base=x;
  688.         if (!xdr_mycallmsg(&xs,r)) { /* the library one just sucks */
  689.             printf ("#CALL: bad\n");
  690.             break;
  691.         }
  692.         /* first, be sure it's really nfs */
  693.         if (r->rm_call.cb_prog != NFS_PROGRAM) {
  694.             fprintf(stderr,"  Non-NFS program on NFS_PORT\n");
  695.             break;
  696.         }
  697.         /* extract auth info */
  698.         uid = -1;    /* default */
  699.         if (r->rm_call.cb_cred.oa_flavor == AUTH_UNIX) {
  700.             XDR xx;
  701.             xdrmem_create(&xx,x,r->rm_call.cb_cred.oa_length,
  702.                      XDR_DECODE);
  703.             xdr_uid(&xx,&uid);
  704.             xdr_destroy(&xx);
  705.         }
  706.         stat = nfscall(src,dst,s,d,uid,&xs,
  707.                 r->rm_xid,r->rm_call.cb_proc);
  708.         break;
  709.         case REPLY:
  710.         if (!xdr_myreplymsg(&xs,r)) {  /* the library one also sucks */
  711.             printf("#REPL: bad\n");
  712.             break;
  713.         }
  714.         stat = nfsreply(src,dst,s,d,&xs,
  715.                  r->rm_xid,r->rm_reply.rp_stat,
  716.                  r->acpted_rply.ar_stat);
  717.                 /* ar_stat contains garbage if it wasn't */
  718.                 /* really accepted, but we never look @ it */
  719.         break;
  720.         default:
  721.         printf ("#bad direction\n");
  722.     }
  723.     xdr_destroy(&xs);
  724.     return stat;
  725. }
  726.  
  727.         
  728.  
  729.  
  730.  
  731. nfscall(src,dst,s,d,uid,arg,xid,proc)
  732.      char *src;
  733.      char *dst;
  734.      u_long s,d;
  735.      u_int uid;
  736.      XDR *arg;
  737.      u_long xid;
  738.      long proc;
  739. {
  740.     nfstrans *t;
  741.     u_long hashval;
  742.     
  743.     /* first make sure it's a reasonable proc # */
  744.     if ((proc<0) || !(proc<RFS_NPROC))
  745.         return 0;
  746.  
  747.     if ((t=(nfstrans *)malloc(sizeof(nfstrans))) == NULL) {
  748.         gc();
  749.         /* try again */
  750.         if((t=(nfstrans *)malloc(sizeof(nfstrans))) == NULL) {
  751.             fprintf(stderr,"Damn, out of memory\n");
  752.             printf("#out transaction memory\n");
  753.             die();
  754.         }
  755.     }
  756.     if ( (*nfs_call_proc[proc])(arg,t)) {
  757.         /* init the transaction and stick it in place on the queue */
  758.         t->s = s;
  759.         t->d = d;
  760.         t->xid=xid;
  761.         t->uid=uid;
  762.         strcpy(t->src,src);
  763.         strcpy(t->dst,dst);
  764.         t->proc = proc;
  765.         t->timestamp = secs;
  766.         t->ser = ser;
  767.         hashval = xid%QSIZE;
  768.         if (hashval>QSIZE) {
  769.             fprintf(stderr,"%u!!!\n",hashval);
  770.             die();
  771.         }
  772.         t->next = transqueue[hashval];
  773.         transqueue[hashval] = t;
  774.         call++;
  775.         nt++;
  776.         return 1;
  777.     } else {
  778.         free(t);
  779.         return 0;
  780.     }
  781. }
  782.  
  783. nfstrans *findanddq();
  784.  
  785.  
  786. nfsreply(src,dst,s,d,arg,xid,stat,astat)
  787.      char *src;
  788.      char *dst;
  789.      u_long s,d;
  790.      XDR *arg;
  791.      long xid;
  792.      long stat;
  793.      long astat;
  794. {
  795.     nfstrans *t;
  796.  
  797.     if ((t=findanddq(s,d,xid)) == NULL) {
  798.         notok++;
  799.         return 0;
  800.     }
  801.     if ((stat!=0)||(astat!=0) || ((*nfs_repl_proc[t->proc])(arg,t) == 0)) {
  802.         ok++;
  803.         nt--;
  804.         free (t);
  805.         return 0;
  806.     }
  807.     size=hsize(t->dst);    /* zero = unknown size */
  808.     emit (t);
  809.     nt--;
  810.     free (t);
  811.     ok++;
  812.     return 1;
  813. }
  814.  
  815.  
  816.  
  817. nfstrans *findanddq(s,d,xid)
  818.      u_long s,d,xid;
  819. {
  820.     nfstrans *t;
  821.     nfstrans *tt;
  822.     nfstrans **ptr;
  823.     u_long hashval;
  824.  
  825.     hashval = xid%QSIZE;
  826.     t=transqueue[hashval];
  827.     ptr = &transqueue[hashval];
  828.     while (t != NULL) {
  829.         if ((t->xid == xid) && (t->s == d) && (t->d == s)) {
  830.             *ptr = t->next;
  831.             return t;
  832.         }
  833.         /* quick gc test */
  834.         if ((secs - t->timestamp) > MAXAGE) {
  835.             fgc++;
  836.             *ptr = t->next;
  837.             tt=t;
  838.             t=t->next;
  839.             nt--;
  840.             free (tt);
  841.         }
  842.         else {
  843.             ptr = &t->next;
  844.             t=t->next;
  845.         }
  846.     }
  847.     return NULL;
  848. }
  849.  
  850.  
  851. gc()
  852. {
  853.     static int i;
  854.     static nfstrans *t, **ptr, *tt;
  855.  
  856.     ngc++;
  857.     printf("# garbage collecting %d\n",nt);
  858.     for (i=0; i<QSIZE; i++) {
  859.         t=transqueue[i];
  860.         ptr = &transqueue[i];
  861.         while (t!=NULL)
  862.             if ((secs-t->timestamp)>MAXAGE) {
  863.                 *ptr = t->next;
  864.                 tt=t;
  865.                 t=t->next;
  866.                 nt--;
  867.                 free (tt);
  868.             } else {
  869.                 ptr = &t->next;
  870.                 t=t->next;
  871.             }
  872.     }
  873.     lastgc=secs;
  874.     printf("#done %d\n",nt);
  875. }
  876.  
  877. emit(t)
  878.      nfstrans *t;
  879. {
  880.     printf("%d.%06d | %s | %s.%d | %s | ",
  881.            secs,ser,t->dst,t->src,t->uid,nfs_proc_name[t->proc]);
  882.     if (!terseflag)
  883.         (*nfs_emit_proc[t->proc])(t);
  884.     printf("\n");
  885. }
  886.  
  887.  
  888. /*
  889.  * functions for the various nfs procedures
  890.  */
  891.  
  892.  
  893. /* NFS_CALL */
  894.  
  895. call_nfs_null(xs,t)
  896.      XDR *xs;
  897.      nfstrans *t;
  898. {
  899.     /* this one's easy; no xdr data */
  900.     return 1;
  901. }
  902.  
  903. repl_nfs_null(xs,t)
  904.      XDR *xs;
  905.      nfstrans *t;
  906. {
  907.     return 1;
  908. }
  909.  
  910. emit_nfs_null(t)
  911.      nfstrans *t;
  912. {
  913.     printf("|");
  914. }
  915.  
  916.  
  917. /* NFS_GETATTR */
  918.  
  919. call_nfs_getattr(xs,t)
  920.      XDR *xs;
  921.      nfstrans *t;
  922. {
  923.     return(xdr_fhandle(xs,&t->args.getattr.call));
  924. }
  925.  
  926. repl_nfs_getattr(xs,t)
  927.      XDR *xs;
  928.      nfstrans *t;
  929. {
  930.     return(xdr_attrstat(xs,&t->args.getattr.reply));
  931. }
  932.  
  933. emit_nfs_getattr(t)
  934.      nfstrans *t;
  935. {
  936.     fhandle_t *call;
  937.     struct nfsattrstat *reply;
  938.  
  939.     call = &t->args.getattr.call;
  940.     reply= &t->args.getattr.reply;
  941.     phandle(call);
  942.     printf("| %s",reply->ns_status?"failed":"ok");
  943.     if (reply->ns_status == NFS_OK) {
  944.         printf(", ");
  945.         printfattr(&reply->ns_attr);
  946.     }
  947. }
  948.  
  949. /* NFS_SETATTR */
  950.  
  951. call_nfs_setattr(xs,t)
  952.      XDR *xs;
  953.      nfstrans *t;
  954. {
  955.     return(xdr_saargs(xs,&t->args.setattr.call));
  956. }
  957.  
  958. repl_nfs_setattr(xs,t)
  959.      XDR *xs;
  960.      nfstrans *t;
  961. {
  962.     return(xdr_attrstat(xs,&t->args.setattr.reply));
  963. }
  964.  
  965. emit_nfs_setattr(t)
  966.      nfstrans *t;
  967. {
  968.     struct nfssaargs *call;
  969.     struct nfsattrstat *reply;
  970.  
  971.     call = &t->args.setattr.call;
  972.     reply= &t->args.setattr.reply;
  973.     printf("{");
  974.     phandle(&call->saa_fh);
  975.     printf(", ");
  976.     printsattr(&call->saa_sa);
  977.     printf("} | %s",reply->ns_status?"failed":"ok");
  978.     if (reply->ns_status == NFS_OK) {
  979.         printf(", ");
  980.         printfattr(&reply->ns_attr);
  981.     }
  982. }
  983.  
  984. /* NFS_ROOT */
  985.  
  986. call_nfs_root(xs,t)
  987.      XDR *xs;
  988.      nfstrans *t;
  989. {
  990.     return 1;
  991. }
  992.  
  993. repl_nfs_root(xs,t)
  994.      XDR *xs;
  995.      nfstrans *t;
  996. {
  997.     return 1;
  998. }
  999.  
  1000. emit_nfs_root(t)
  1001.      nfstrans *t;
  1002. {
  1003.     printf("|");
  1004. }
  1005.  
  1006. /* NFS_LOOKUP */
  1007.  
  1008. call_nfs_lookup(xs,t)
  1009.      XDR *xs;
  1010.      nfstrans *t;
  1011. {
  1012.     /* ok, this one's a bit tricky, because we have to set up pointers */
  1013.     t->args.lookup.call.da_name = t->b1;
  1014.     return(xdr_diropargs(xs,&t->args.lookup.call));
  1015. }
  1016.  
  1017. repl_nfs_lookup(xs,t)
  1018.      XDR *xs;
  1019.      nfstrans *t;
  1020. {
  1021.     return(xdr_diropres(xs,&t->args.lookup.reply));
  1022. }
  1023.  
  1024. emit_nfs_lookup(t)
  1025.      nfstrans *t;
  1026. {
  1027.     struct nfsdiropargs *call;
  1028.     struct nfsdiropres *reply;
  1029.  
  1030.     call = &t->args.lookup.call;
  1031.     reply= &t->args.lookup.reply;
  1032.     printdiropargs(call);
  1033.     printf(" | %s",reply->dr_status?"failed":"ok");
  1034.     if (reply->dr_status == NFS_OK) {
  1035.         printf(", ");
  1036.         printdiropres(reply);
  1037.     }
  1038. }
  1039.  
  1040. /* NFS_READLINK */
  1041.  
  1042. call_nfs_readlink(xs,t)
  1043.      XDR *xs;
  1044.      nfstrans *t;
  1045. {
  1046.     return(xdr_fhandle(xs,&t->args.readlink.call));
  1047. }
  1048.  
  1049. repl_nfs_readlink(xs,t)
  1050.      XDR *xs;
  1051.      nfstrans *t;
  1052. {
  1053.     t->args.readlink.reply.rl_data = t->b1;
  1054.     return(xdr_rdlnres(xs,&t->args.readlink.reply));
  1055. }
  1056.  
  1057. emit_nfs_readlink(t)
  1058.      nfstrans *t;
  1059. {
  1060.     fhandle_t *call;
  1061.     struct nfsrdlnres *reply;
  1062.  
  1063.     call = &t->args.readlink.call;
  1064.     reply= &t->args.readlink.reply;
  1065.     phandle(call);
  1066.     printf("| %s",reply->rl_status?"failed":"ok");
  1067.     if (reply->rl_status == NFS_OK) {
  1068.         printf(", ");
  1069.         reply->rl_data[reply->rl_count] = '\0';
  1070.         printstr(reply->rl_data);
  1071.     }
  1072. }
  1073.  
  1074. /* NFS_READ */
  1075.  
  1076. call_nfs_read(xs,t)
  1077.      XDR *xs;
  1078.      nfstrans *t;
  1079. {
  1080.     return(xdr_readargs(xs,&t->args.read.call));
  1081. }
  1082.  
  1083. repl_nfs_read(xs,t)
  1084.      XDR *xs;
  1085.      nfstrans *t;
  1086. {
  1087.     static char buf[MTU];    /* garbage place to store data */
  1088.  
  1089.     t->args.read.reply.rr_data = buf;
  1090.     return(xdr_rdresult(xs,&t->args.read.reply));
  1091. }
  1092.  
  1093. emit_nfs_read(t)
  1094.      nfstrans *t;
  1095. {
  1096.     struct nfsreadargs *call;
  1097.     struct nfsrdresult *reply;
  1098.  
  1099.     call = &t->args.read.call;
  1100.     reply= &t->args.read.reply;
  1101.     printf("{");
  1102.     phandle(&call->ra_fhandle);
  1103.     printf(", %d, %d} |",
  1104.            call->ra_offset,
  1105.            call->ra_count);
  1106.     printf(" %s",reply->rr_status?"failed":"ok");
  1107.     if (reply->rr_status == NFS_OK) {
  1108.         printf(", %d",reply->rr_count);
  1109.     }
  1110. }
  1111.  
  1112. /* NFS_WRITECACHE */
  1113.  
  1114. call_nfs_writecache(xs,t)
  1115.      XDR *xs;
  1116.      nfstrans *t;
  1117. {
  1118.     return 1;
  1119. }
  1120.  
  1121. repl_nfs_writecache(xs,t)
  1122.      XDR *xs;
  1123.      nfstrans *t;
  1124. {
  1125.     return 1;
  1126. }
  1127.  
  1128. emit_nfs_writecache(t)
  1129.      nfstrans *t;
  1130. {
  1131.     printf("|");
  1132. }
  1133.  
  1134. /* NFS_WRITE */
  1135.  
  1136. call_nfs_write(xs,t)
  1137.      XDR *xs;
  1138.      nfstrans *t;
  1139. {
  1140.     static char buf[MTU];    /* another garbage place */
  1141.  
  1142.     t->args.write.call.wa_data = buf;
  1143.     return(xdr_writeargs(xs,&t->args.write.call));
  1144. }
  1145.  
  1146. repl_nfs_write(xs,t)
  1147.      XDR *xs;
  1148.      nfstrans *t;
  1149. {
  1150.     return(xdr_attrstat(xs,&t->args.write.reply));
  1151. }
  1152.  
  1153. emit_nfs_write(t)
  1154.      nfstrans *t;
  1155. {
  1156.     struct nfswriteargs *call;
  1157.     struct nfsattrstat *reply;
  1158.  
  1159.     call = &t->args.write.call;
  1160.     reply= &t->args.write.reply;
  1161.     printf("{");
  1162.     phandle(&call->wa_fhandle);
  1163.     printf(", %d, %d} |",
  1164.            call->wa_offset,
  1165.            call->wa_count);
  1166.     printf(" %s",reply->ns_status?"failed":"ok");
  1167.     if (reply->ns_status == NFS_OK) {
  1168.         printf(", ");
  1169.         printfattr(&reply->ns_attr);
  1170.     }
  1171. }
  1172.  
  1173. /* NFS_CREATE */
  1174.  
  1175. call_nfs_create(xs,t)
  1176.      XDR *xs;
  1177.      nfstrans *t;
  1178. {
  1179.     t->args.create.call.ca_da.da_name = t->b3;
  1180.     return(xdr_creatargs(xs,&t->args.create.call));
  1181. }
  1182.  
  1183. repl_nfs_create(xs,t)
  1184.      XDR *xs;
  1185.      nfstrans *t;
  1186. {
  1187.     return(xdr_diropres(xs,&t->args.create.reply));
  1188. }
  1189.  
  1190. emit_nfs_create(t)
  1191.      nfstrans *t;
  1192. {
  1193.     struct nfscreatargs *call;
  1194.     struct nfsdiropres *reply;
  1195.  
  1196.     call = &t->args.create.call;
  1197.     reply= &t->args.create.reply;
  1198.     printf("{");
  1199.     phandle(&call->ca_da.da_fhandle);
  1200.     printf(", ");
  1201.     printstr(call->ca_da.da_name);
  1202.     printf(", ");
  1203.     printsattr(&call->ca_sa);
  1204.     printf("} | %s",reply->dr_status?"failed":"ok");
  1205.     if (reply->dr_status == NFS_OK) {
  1206.         printf(", {");
  1207.         phandle(&reply->dr_fhandle);
  1208.         printf(", ");
  1209.         printfattr(&reply->dr_attr);
  1210.         printf("}");
  1211.     }
  1212. }
  1213.  
  1214. /* NFS_REMOVE */
  1215.  
  1216. call_nfs_remove(xs,t)
  1217.      XDR *xs;
  1218.      nfstrans *t;
  1219. {
  1220.     t->args.remove.call.da_name = t->b3;
  1221.     return(xdr_diropargs(xs,&t->args.remove.call));
  1222. }
  1223.  
  1224. repl_nfs_remove(xs,t)
  1225.      XDR *xs;
  1226.      nfstrans *t;
  1227. {
  1228.     return(xdr_enum(xs,&t->args.remove.reply));
  1229. }
  1230.  
  1231.  
  1232. emit_nfs_remove(t)
  1233.      nfstrans *t;
  1234. {
  1235.     struct nfsdiropargs *call;
  1236.     enum nfsstat *reply;
  1237.  
  1238.     call = &t->args.remove.call;
  1239.     reply= &t->args.remove.reply;
  1240.     printdiropargs(call);
  1241.     printf(" | %s", *reply?"failed":"ok");
  1242. }
  1243.  
  1244. /* NFS_RENAME */
  1245.  
  1246. call_nfs_rename(xs,t)
  1247.      XDR *xs;
  1248.      nfstrans *t;
  1249. {
  1250.     t->args.rename.call.rna_from.da_name = t->b3;
  1251.     t->args.rename.call.rna_to.da_name = t->b4;
  1252.     return(xdr_rnmargs(xs,&t->args.rename.call));
  1253. }
  1254.  
  1255. repl_nfs_rename(xs,t)
  1256.      XDR *xs;
  1257.      nfstrans *t;
  1258. {
  1259.     return(xdr_enum(xs,&t->args.rename.reply));
  1260. }
  1261.  
  1262.  
  1263. emit_nfs_rename(t)
  1264.      nfstrans *t;
  1265. {
  1266.     struct nfsrnmargs *call;
  1267.     enum nfsstat *reply;
  1268.  
  1269.     call = &t->args.rename.call;
  1270.     reply= &t->args.rename.reply;
  1271.     printdiropargs(&call->rna_from);
  1272.     printf(", ");
  1273.     printdiropargs(&call->rna_to);
  1274.     printf(" | %s",*reply?"failed":"ok");
  1275. }
  1276.  
  1277. /* NFS_LINK */
  1278.  
  1279. call_nfs_link(xs,t)
  1280.      XDR *xs;
  1281.      nfstrans *t;
  1282. {
  1283.     t->args.link.call.la_to.da_name = t->b3;
  1284.     return(xdr_linkargs(xs,&t->args.link.call));
  1285. }
  1286.  
  1287. repl_nfs_link(xs,t)
  1288.      XDR *xs;
  1289.      nfstrans *t;
  1290. {
  1291.     return(xdr_enum(xs,&t->args.link.reply));
  1292. }
  1293.  
  1294. emit_nfs_link(t)
  1295.      nfstrans *t;
  1296. {
  1297.     struct nfslinkargs *call;
  1298.     enum nfsstat *reply;
  1299.  
  1300.     call = &t->args.link.call;
  1301.     reply= &t->args.link.reply;
  1302.     printf("{");
  1303.     phandle(&call->la_from);
  1304.     printf(", ");
  1305.     printdiropargs(&call->la_to);
  1306.     printf("} | %s",*reply?"failed":"ok");
  1307. }
  1308.  
  1309. /* NFS_SYMLINK */
  1310.  
  1311. call_nfs_symlink(xs,t)
  1312.      XDR *xs;
  1313.      nfstrans *t;
  1314. {
  1315.     t->args.symlink.call.sla_from.da_name = t->b3;
  1316.     t->args.symlink.call.sla_tnm = t->b1;
  1317.     return(xdr_slargs(xs,&t->args.symlink.call));
  1318. }
  1319.  
  1320. repl_nfs_symlink(xs,t)
  1321.      XDR *xs;
  1322.      nfstrans *t;
  1323. {
  1324.     return(xdr_enum(xs,&t->args.symlink.reply));
  1325. }
  1326.  
  1327.  
  1328. emit_nfs_symlink(t)
  1329.      nfstrans *t;
  1330. {
  1331.     struct nfsslargs *call;
  1332.     enum nfsstat *reply;
  1333.  
  1334.     call = &t->args.symlink.call;
  1335.     reply= &t->args.symlink.reply;
  1336.     printf("{");
  1337.     printdiropargs(&call->sla_from);
  1338.     printf(", ");
  1339.     printstr(call->sla_tnm);
  1340.     printf(", ");
  1341.     printsattr(&call->sla_sa);
  1342.     printf("} | %s",*reply?"failed":"ok");
  1343. }
  1344.  
  1345. /* NFS_MKDIR */
  1346.  
  1347. call_nfs_mkdir(xs,t)
  1348.    XDR *xs;
  1349.    nfstrans *t;
  1350. {
  1351.     t->args.mkdir.call.ca_da.da_name = t->b3;
  1352.     return(xdr_creatargs(xs,&t->args.mkdir.call));
  1353. }
  1354.  
  1355. repl_nfs_mkdir(xs,t)
  1356.      XDR *xs;
  1357.      nfstrans *t;
  1358. {
  1359.     return(xdr_diropres(xs,&t->args.mkdir.reply));
  1360. }
  1361.  
  1362. emit_nfs_mkdir(t)
  1363.      nfstrans *t;
  1364. {
  1365.     struct nfscreatargs *call;
  1366.     struct nfsdiropres *reply;
  1367.  
  1368.     call = &t->args.mkdir.call;
  1369.     reply= &t->args.mkdir.reply;
  1370.     printf("{");
  1371.     phandle(&call->ca_da.da_fhandle);
  1372.     printf(", ");
  1373.     printstr(call->ca_da.da_name);
  1374.     printf(", ");
  1375.     printsattr(&call->ca_sa);
  1376.     printf("} | %s",reply->dr_status?"failed":"ok");
  1377.     if (reply->dr_status == NFS_OK) {
  1378.         printf(", {");
  1379.         phandle(&reply->dr_fhandle);
  1380.         printf(", ");
  1381.         printfattr(&reply->dr_attr);
  1382.         printf("}");
  1383.     }
  1384. }
  1385.  
  1386. /* NFS_RMDIR */
  1387.  
  1388. call_nfs_rmdir(xs,t)
  1389.      XDR *xs;
  1390.      nfstrans *t;
  1391. {
  1392.     t->args.rmdir.call.da_name = t->b3;
  1393.     return(xdr_diropargs(xs,&t->args.rmdir.call));
  1394. }
  1395.  
  1396. repl_nfs_rmdir(xs,t)
  1397.      XDR *xs;
  1398.      nfstrans *t;
  1399. {
  1400.     return(xdr_enum(xs,&t->args.rmdir.reply));
  1401. }
  1402.  
  1403. emit_nfs_rmdir(t)
  1404.      nfstrans *t;
  1405. {
  1406.     struct nfsdiropargs *call;
  1407.     enum nfsstat *reply;
  1408.  
  1409.     call = &t->args.rmdir.call;
  1410.     reply= &t->args.rmdir.reply;
  1411.     printdiropargs(call);
  1412.     printf(" | %s",*reply?"failed":"ok");
  1413. }
  1414.  
  1415. /* NFS_READDIR */
  1416.  
  1417. call_nfs_readdir(xs,t)
  1418.      XDR *xs;
  1419.      nfstrans *t;
  1420. {
  1421.     return(xdr_rddirargs(xs,&t->args.readdir.call));
  1422. }
  1423.  
  1424. repl_nfs_readdir(xs,t)
  1425.      XDR *xs;
  1426.      nfstrans *t;
  1427. {
  1428.     t->args.readdir.reply.rd_entries = NULL;  /* we dont use */
  1429.     return(xdr_getrddirres(xs,&t->args.readdir.reply));
  1430. }
  1431.  
  1432. emit_nfs_readdir(t)
  1433.      nfstrans *t;
  1434. {
  1435.     fhandle_t *call;
  1436.     struct nfsattrstat *reply;
  1437.  
  1438.     phandle(&t->args.readdir.call.rda_fh);
  1439.     printf(" | %s",t->args.readdir.reply.rd_status?"failed":"ok");
  1440.  
  1441. }
  1442.  
  1443. /* NFS_STATFS */
  1444.  
  1445. call_nfs_statfs(xs,t)
  1446.      XDR *xs;
  1447.      nfstrans *t;
  1448. {
  1449.     return(xdr_fhandle(xs,&t->args.statfs.call));
  1450. }
  1451.  
  1452. repl_nfs_statfs(xs,t)
  1453.      XDR *xs;
  1454.      nfstrans *t;
  1455. {
  1456.     return(xdr_statfs(xs,&t->args.readdir.reply));
  1457. }
  1458.  
  1459. emit_nfs_statfs(t)
  1460.      nfstrans *t;
  1461. {
  1462.     fhandle_t *call;
  1463.     struct nfsattrstat *reply;
  1464.  
  1465.     printf(" |");
  1466.     return 1;
  1467. }
  1468.  
  1469. #define HSIZE 14 /* max reasonable handle size for funny file handles */
  1470. #define min(x,y) ((x)>(y)?(y):(x))
  1471.  
  1472. phandle(h)
  1473.      fhandle_t *h;
  1474. {
  1475.     u_long i;
  1476.     u_long j;
  1477.     u_char *p;
  1478.     unsigned char buf[64];
  1479.     int si;
  1480.  
  1481.     buf[0]='\0';
  1482.     j=min(h->fh_len,ntohs(h->fh_len));
  1483.     j-=4;
  1484.     si=size;
  1485.     if (si) {
  1486.         p=(u_char *)h;
  1487.         while(si--)
  1488.             sprintf(buf,"%s%02x",buf,*(p++));
  1489.     } else if (((j<0) || (j>FHMAXDATA)) || /* guess size */
  1490.         !(h->fh_fsid.val[0]+h->fh_fsid.val[1])) {/* funny (utrix/mach) */
  1491.         p = (u_char *) h;
  1492.         for (i=0; i<HSIZE; i++)
  1493.             sprintf(buf,"%s%02x",buf,p[i]);
  1494.     } else {                /* regular kind */
  1495.         sprintf(buf,"%08x%08x",(h->fh_fsid.val[0]),
  1496.                (h->fh_fsid.val[1]));
  1497.         for(i=0;i<j; i++)
  1498.             sprintf(buf,"%s%02x",buf,(unsigned char)h->fh_data[i]);
  1499.     }
  1500.     p=buf;
  1501.     while (*p && (*p=='0'))
  1502.         p++;
  1503.     printf("\"%s\"",p);
  1504. }
  1505.  
  1506.  
  1507. /*
  1508.  * XDR routines
  1509.  */
  1510.  
  1511.  
  1512. xdr_uid(xs,u)
  1513.      XDR *xs;
  1514.      u_int *u;
  1515. {
  1516.     static char junk[255];
  1517.     u_int stamp;
  1518.     return (xdr_int(xs,&stamp) && xdr_string(xs,junk,255)
  1519.         && xdr_u_int(xs,u));
  1520. }
  1521.  
  1522.  
  1523. xdr_myreplymsg(xs,r)
  1524.      XDR *xs;
  1525.      struct rpc_msg *r;
  1526. {
  1527.     static char x[MAX_AUTH_BYTES];
  1528.     
  1529.     if (xdr_u_long(xs, &(r->rm_xid)) &&
  1530.         xdr_enum(xs, &(r->rm_direction)) &&
  1531.         (r->rm_direction==REPLY) &&
  1532.         xdr_enum(xs, &(r->rm_reply.rp_stat)) &&
  1533.         (r->rm_reply.rp_stat==MSG_ACCEPTED) &&  /* ignore if rejected */
  1534.         ((r->acpted_rply.ar_verf.oa_base=x),1) && /* this is disgusting */
  1535.         xdr_opaque_auth(xs, &(r->acpted_rply.ar_verf)))
  1536.         return (xdr_enum(xs, &(r->acpted_rply.ar_stat)));
  1537.     return (FALSE);
  1538.     /* note that we now point to the begining of the reply data */
  1539. }
  1540.  
  1541. xdr_mycallmsg(xs,r)
  1542.      XDR *xs;
  1543.      struct rpc_msg *r;
  1544. {
  1545.     static char x[MAX_AUTH_BYTES];    /* stupid ugly hack */
  1546.  
  1547.         if (xdr_u_long(xs, &(r->rm_xid)) &&
  1548.             xdr_enum(xs, &(r->rm_direction)) &&
  1549.             (r->rm_direction == CALL) &&
  1550.             xdr_u_long(xs, &(r->rm_call.cb_rpcvers)) &&
  1551.             (r->rm_call.cb_rpcvers == RPC_MSG_VERSION) &&
  1552.             xdr_u_long(xs, &(r->rm_call.cb_prog)) &&
  1553.             xdr_u_long(xs, &(r->rm_call.cb_vers)) &&
  1554.             xdr_u_long(xs, &(r->rm_call.cb_proc)) &&
  1555. /*        ((r->rm_call.cb_cred.oa_base=x),1) && */
  1556.             xdr_opaque_auth(xs, &(r->rm_call.cb_cred))) {
  1557.         r->rm_call.cb_verf.oa_base=x;
  1558.         return (xdr_opaque_auth(xs, &(r->rm_call.cb_verf)));
  1559.     }
  1560.     return FALSE;
  1561. }
  1562.  
  1563.  
  1564. printdiropres(r)
  1565.      struct nfsdiropres *r;
  1566. {
  1567.     printf("{");
  1568.     phandle(&r->dr_fhandle);
  1569.     printf(", ");
  1570.     printfattr(&r->dr_attr);
  1571.     printf("}");
  1572. }
  1573.  
  1574.  
  1575. printfattr(f)
  1576.      struct nfsfattr *f;
  1577. {
  1578.     printf("{0%o, %d, %d, 0x%x}",
  1579.                f->na_mode,
  1580.               f->na_uid,
  1581.                f->na_size,
  1582.             f->na_nodeid);
  1583. }
  1584.  
  1585. printsattr(s)
  1586.      struct nfssattr *s;
  1587. {
  1588.     printf("{0%o, %d, %d}",
  1589.            s->sa_mode,
  1590.            s->sa_uid,
  1591.            s->sa_size);
  1592. }
  1593.  
  1594.  
  1595. printdiropargs(d)
  1596.      struct nfsdiropargs *d;
  1597. {
  1598.     printf("{");
  1599.     phandle(&d->da_fhandle);
  1600.     printf(", ");
  1601.     printstr(d->da_name);
  1602.     printf("}");
  1603. }
  1604.  
  1605. printstr(s)
  1606.      char *s;
  1607. {
  1608.     putchar('\"');
  1609.     while (*s) {
  1610.         switch (*s) {
  1611.             case '\\':
  1612.             case '\n':
  1613.             case '\"':
  1614.             case '|':
  1615.             putchar('\\');
  1616.             default:
  1617.             putchar (*s);
  1618.         }
  1619.         ++s;
  1620.     }
  1621.     putchar('\"');
  1622. }
  1623.